Análisis de Negocio¶

El desarrollo de este Notebook se centra en analizar el comportamiento de un negocio digital en línea que conecta pequeñas empresas de Colombia, a través del uso de un sólo canal y un sólo contrato. Los comerciantes pueden vender sus productos a través de una tienda en línea y enviarlo directamente a los clientes a través de múltiples empresas logísticas aliadas. Además, luego de que un cliente compra el producto en la tienda el línea, el vendedor recibe una notificación y permite finalizar la transacción. Por otra parte, una vez que el cliente recibe el producto, o la fecha estimada de entrega se vence, el cliente recibe una encuesta de satisfacción por correo electrónico donde puede evaluar la experiencia de compra y agregar algunos comentarios.

Para el análisis vamos a emplear un conjunto de datos que contiene información de alrededor 10k pedidos realizados entre los años 2016 a 2018 que involucran múltiples comercios en Colombia, en este conjunto de datos podemos encontrar el estado del pedido, el precio, el pago, el desempeño del flete, la ubicación del cliente, los atributos del producto y finalmente las reseñas escritas por los clientes.

Objetivo:¶

El onjetivo principal es identificar las principales características sobre envíos, precios, valor de fletes y múltiples variables adicionales con el fin de estudiar el comportamiento que presentan las ventas a través del negocio digital. De manera específica lograremos:

  1. Preparar el conjunto de datos y validar su calidad para emplear en el análisis propuesto.
  2. Identificar las principales características en los datos a través del uso de estadística univariada y estadística bivariada.
  3. Responder preguntas acerca del comportamiento de algunas variables del negocio.
  4. Transformar la información proporcionada por el conjunto de datos en representaciones visuales a través de la visualización de datos en Python con el objetivo de analizar la información y comunicar de manera más efectivas las conclusiones obtenidas.

Conocimientos aplicados¶

  1. Carga de archivos mediante Pandas.
  2. Preparación y validación de la calidad del conjunto de datos a emplear.
  3. Análisis exploratorio de datos.
  4. Estadística univariada.
  5. Visualización de datos con Python.

1. Importación de librerías y archivos¶

En las siguientes líneas de código vamos a importar las librerías a utilizar en el análisis de las características del negocio, así como los archivos que contienen el conjunto de datos.

In [1]:
#Importamos las liberías necesarias para realizar el análisis de interés.
import pandas as pd #librería para manejo de datos.
from datetime import date #librería para manejar tipo de datos datetime.
import numpy as np #librería para cálculos matemáticos.
#nos permite analizar gráficos a través del mouse y redimencionarlas a conveniencia.
import plotly.io as pio
pio.renderers.default='notebook'
import plotly.express as px
import random #para generar valores aleatorios
from IPython.display import IFrame #para incluir archivos html en el notebook.

#cargamos el conjunto de datos a emplear.
data_ordenes=pd.read_csv('Ordenes_productos_C1_M2.3.csv', sep=';')
data_ordenes.head()
Out[1]:
orden_id order_item_id producto_id vendedor_id fecha_envio_limite precio valor_flete codigo_postal_vendedor ciudad_vendedor departamento_vendedor nombre_categoria_producto longitud_nombre_producto longitud_descripcion_producto cantidad_fotos_producto peso_g_producto longitud_cm_producto altura_cm_producto ancho_cm_producto
0 107500PO59A A PO59 VE5389 7/04/2018 18:12 271.86 30.72 52435 Mallama Nariño Productos ecoamigables 6.0 7.0 27.0 2486.0 17.0 11.0 14.0
1 37493PS22B B PS22 VE1558 20/10/2017 9:07 115.73 4.68 52203 Colon Nariño Carnicería 10.0 31.0 20.0 256.0 43.0 2.0 21.0
2 28050PK20B B PK20 VE9159 17/08/2017 8:15 432.99 82.70 66001 Pereira Risaralda Deportes 25.0 5.0 4.0 5270.0 9.0 27.0 29.0
3 52187PA10A A PA10 VE3159 23/09/2017 23:27 108.38 35.39 52435 Mallama Nariño Electrodomésticos 10.0 1.0 6.0 734.0 46.0 48.0 22.0
4 84639PR12A A PR12 VE5090 7/01/2018 11:50 51.50 11.10 73001 Ibague Tolima Frutas y verduras 23.0 16.0 35.0 884.0 45.0 26.0 18.0
In [2]:
#validamos en tamaño de nuestro conjunto de datos. 
data_ordenes.shape
Out[2]:
(10134, 18)

El conjunto de datos: observamos que el conjunto de datos posee un total de 10134 registros y 18 atributos.

2. Validación de la calidad de los datos¶

Una vez hallamos importado las librerías y el archivo a emplear para el análisis, validaremos cuál es la calidad que presentan dichos datos con el fin de identificar si hay problemas presentes en las dimensiones de calidad relacionadas a la completitud, estandarización, duplicidad y consistencia de los datos.

2.1 Completitud¶

Objetivos¶

  1. Revisar los atributos que contienen datos vacíos.
  2. Aplicar diversas formas para mejorar la dimensión de completitud de la columnas de la fuente de datos analizada.
In [3]:
#identificamos cuantos datos vacíos se presenta en cada uno de los atributos del dataset.
data_ordenes.isna().sum()
Out[3]:
orden_id                          0
order_item_id                     0
producto_id                       0
vendedor_id                       0
fecha_envio_limite                0
precio                            0
valor_flete                       0
codigo_postal_vendedor            0
ciudad_vendedor                   0
departamento_vendedor             0
nombre_categoria_producto        23
longitud_nombre_producto         23
longitud_descripcion_producto    23
cantidad_fotos_producto          23
peso_g_producto                  23
longitud_cm_producto             23
altura_cm_producto               23
ancho_cm_producto                23
dtype: int64
In [4]:
#Identificamos el porcentaje de datos vacíos para cada atributo con datos vacíos.
data_ordenes[["nombre_categoria_producto",
"longitud_nombre_producto",
"longitud_descripcion_producto",
"cantidad_fotos_producto",
"peso_g_producto",
"longitud_cm_producto",
"altura_cm_producto",
"ancho_cm_producto"]].isna().sum()/len(data_ordenes)*100
Out[4]:
nombre_categoria_producto        0.226959
longitud_nombre_producto         0.226959
longitud_descripcion_producto    0.226959
cantidad_fotos_producto          0.226959
peso_g_producto                  0.226959
longitud_cm_producto             0.226959
altura_cm_producto               0.226959
ancho_cm_producto                0.226959
dtype: float64

Conclusión de calidad de los datos en la dimensión de completitud: podemos observar que hay un total de 23 valores vacíos en los últimos 8 atributos del data set, los cuales se relacionan con la descripción de las características del producto vendido, decidimos eliminar los registros con valores faltantes debido a que no representan más del 0.3% de todo el conjunto de datos.

In [5]:
#eliminamos los registros vacíos del conjunto de datos.
data_ordenes.dropna(inplace=True)

2.2 Estandarización¶

Objetivos¶

  1. Identificar problemas de estandarización en el data set.
  2. Plantear alternativas para resolver los problemas de falta de estandarización en caso de ser necesario.
  3. Automatizar la estandarización de los datos en caso de ser necesario.

Diccionario de datos¶

image-2.png

In [6]:
#en primer lugar vamos a validar que cada uno de los atributos tenga el tipo de dato definido en el dicionario de datos. 
data_ordenes.dtypes
Out[6]:
orden_id                          object
order_item_id                     object
producto_id                       object
vendedor_id                       object
fecha_envio_limite                object
precio                           float64
valor_flete                      float64
codigo_postal_vendedor             int64
ciudad_vendedor                   object
departamento_vendedor             object
nombre_categoria_producto         object
longitud_nombre_producto         float64
longitud_descripcion_producto    float64
cantidad_fotos_producto          float64
peso_g_producto                  float64
longitud_cm_producto             float64
altura_cm_producto               float64
ancho_cm_producto                float64
dtype: object

Tipos de datos: observamos que para el caso de la columna "fecha_envio_limite" el tipo de dato no coincide con el descrito en el diccionario de datos. Por lo tanto debemos hacer a conversión del tipo de dato de esta columna a datetime.

In [7]:
#cambiamos el formato de la columna "fecha_envio_limite" a datetime.
data_ordenes['fecha_envio_limite']=pd.to_datetime(data_ordenes['fecha_envio_limite'],format="%d/%m/%Y %H:%M")
#evidenciamos que el cambio se realizó
data_ordenes[["fecha_envio_limite"]].dtypes
Out[7]:
fecha_envio_limite    datetime64[ns]
dtype: object
In [27]:
#A simple vista no se observa que hayan problemas de calidad en los datos relacionados con la estandarización a parte del
#tipo de dato de la columna "fecha_envio_limite".Haremos un recuento de las categorías en los atributos categóricos 
#para verificar más a fondo si existen o no más problemas en la estandarización.

#seleccionamos sólo los atributos categóricos presentes en el dataset.
data_catego=data_ordenes.select_dtypes(include=["object"])
#Revisamos las categorías presentes en cada una de los atributos categóricos.
for i in data_catego.columns:
   print(data_catego[i].value_counts().reset_index(),"\n")
          orden_id  count
0      107500PO59A      1
1       48085PT66A      1
2       24209PR85B      1
3       36058PB41A      1
4       16627PF73A      1
...            ...    ...
10106   66486PD96A      1
10107    7966PM62A      1
10108   71397PC34A      1
10109  105032PF27A      1
10110   48674PC53A      1

[10111 rows x 2 columns] 

   order_item_id  count
0              A   8861
1              B    906
2              C    188
3              D     80
4              E     34
5              F     22
6              G      5
7              H      4
8              I      4
9              J      3
10             M      1
11             O      1
12             N      1
13             L      1 

     producto_id  count
0           PO55     15
1           PB63     15
2           PF78     14
3           PM57     13
4           PB32     13
...          ...    ...
1788        PR62      1
1789        PK48      1
1790        PB84      1
1791        PF58      1
1792        PF11      1

[1793 rows x 2 columns] 

    vendedor_id  count
0        VE3276    117
1        VE8511    115
2        VE5049    111
3        VE3791     72
4        VE3215     69
..          ...    ...
192      VE1340     35
193      VE9276     35
194      VE8942     33
195      VE3159     31
196      VE8903     30

[197 rows x 2 columns] 

   ciudad_vendedor  count
0        Gualmatan    428
1          Pereira    405
2    Villavicencio    404
3        Manizales    376
4          Acacias    357
..             ...    ...
66          Ospina     15
67        Abriaqui     15
68          Acandi     13
69         Acevedo     12
70           Neiva      4

[71 rows x 2 columns] 

   departamento_vendedor  count
0                 Nariño   3642
1                   Meta   1257
2     Norte de santander    469
3              Risaralda    405
4                 Caldas    376
5              Antioquia    363
6        Valle del cauca    338
7                  Sucre    287
8              Atlantico    224
9               Casanare    224
10               Cordoba    215
11               Bolivar    194
12                Vaupes    187
13                 Cauca    185
14           Bogota d.c.    178
15             Santander    166
16               Guainia    158
17                 Choco    153
18              Amazonas    145
19                Arauca    130
20               Caqueta    116
21            La guajira    110
22          Cundinamarca    101
23                Tolima     95
24              Guaviare     92
25                 Cesar     72
26                Boyaca     62
27            San andres     41
28               Quindio     34
29              Putumayo     28
30             Magdalena     26
31               Vichada     22
32                 Huila     16 

   nombre_categoria_producto  count
0                 Tecnología    542
1                   Deportes    537
2          Frutas y verduras    531
3                 Carnicería    523
4            Ropa de adultos    521
5                 Ferretería    518
6                   Juguetes    516
7              Ropa infantil    511
8          Electrodomésticos    509
9                 Dormitorio    508
10                   Lácteos    499
11                    Libros    497
12    Productos ecoamigables    497
13                  Mascotas    495
14           Tarjetas regalo    495
15                     Salud    488
16                 Celulares    488
17                   Muebles    486
18                     Licor    475
19                    Bebés     475 

Conclusión de calidad de los datos en la dimensión de completitud: vemos que además del problema con el tipo de dato de la columna de fechas de envío, no se presentan más problemas de estandarización, pues observamos que no hay repetición de categorías por errores en el formato de escritura de estás.

2.3 Duplicidad en los datos¶

Objetivos¶

  1. Revisar los registros que contienen datos duplicados ya sea de manera parcial o total.
  2. Aplicar diversas formas para mejorar la dimensión de duplicidad de los registros de la fuente de datos analizada.
In [9]:
#en primer lugar vamos a revisar si hay presencia de duplicados en el identificador único de la orden de venta.
val_uniq=len(data_ordenes["orden_id"].unique())
val_dupli=data_ordenes.duplicated("orden_id").sum()
print("valores únicos:",val_uniq)
print("Valores duplicados en identificador único:",val_dupli)
valores únicos: 10111
Valores duplicados en identificador único: 0
In [10]:
#vamos a revisar si hay valores duplicados parcialmente en todo el conjunto de datos.
print("Valores duplicados en el data set:",data_ordenes.duplicated().sum())
#Revisamos la proporción de duplicidad en los atributos del dataset
data_ordenes[data_ordenes.duplicated()].count()
Valores duplicados en el data set: 0
Out[10]:
orden_id                         0
order_item_id                    0
producto_id                      0
vendedor_id                      0
fecha_envio_limite               0
precio                           0
valor_flete                      0
codigo_postal_vendedor           0
ciudad_vendedor                  0
departamento_vendedor            0
nombre_categoria_producto        0
longitud_nombre_producto         0
longitud_descripcion_producto    0
cantidad_fotos_producto          0
peso_g_producto                  0
longitud_cm_producto             0
altura_cm_producto               0
ancho_cm_producto                0
dtype: int64

Conclusión de calidad de los datos en la dimensión de duplicidad: observamos que no hay presencia de registros duplicados parcialmente o completamente en el conjunto de datos, y lo comprobamos tanto a nivel de identificiador único como a nivel global del set de datos.

2.4 Consistencia¶

Objetivos¶

  1. Revisar los atributos numéricos y revisar si presentan inconsistencias en su dominio.
  2. Aplicar diversas formas para mejorar la dimensión de completitud de la columnas de la fuente de datos analizada.
In [11]:
#Revisamos de manera rápida las variables estadísticas de los atributos numéricos con el fin de determinar si hay inconsistencia.
data_ordenes.describe()
Out[11]:
fecha_envio_limite precio valor_flete codigo_postal_vendedor longitud_nombre_producto longitud_descripcion_producto cantidad_fotos_producto peso_g_producto longitud_cm_producto altura_cm_producto ancho_cm_producto
count 10111 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.00000
mean 2018-01-03 05:02:30.406488064 119.868468 20.062207 49995.607457 20.070023 19.844724 20.097616 2106.475522 30.067352 17.911186 22.91257
min 2017-07-13 22:38:00 0.010000 0.000000 5001.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.00000
25% 2017-10-08 11:40:00 34.175000 5.760000 50001.000000 10.000000 10.000000 10.000000 607.000000 19.000000 9.000000 15.00000
50% 2018-01-03 06:13:00 83.180000 13.990000 52323.000000 20.000000 20.000000 20.000000 1459.000000 30.000000 17.000000 23.00000
75% 2018-04-01 03:34:30 165.640000 27.475000 54003.000000 30.000000 30.000000 30.000000 2941.000000 41.000000 26.000000 30.00000
max 2018-06-26 02:19:00 1262.940000 183.150000 99001.000000 40.000000 40.000000 40.000000 20661.000000 91.000000 64.000000 72.00000
std NaN 119.386311 20.111832 22461.742889 11.719844 11.851631 11.802373 2094.402206 15.286299 11.359838 11.15189

Conclusión de calidad de los datos en la dimensión de consistencia: podemos observar que los valores mínimos de la mayoría de categorías son 0.0 y para el caso del precio del producto es de 0.010 lo que nos hace preguntarnos si es un error del precio real del producto o si es el precio verdadero; lo mismo sucede con el atributo "codigo_postal_vendedor" en dónde podemos evidenciar que hay códigos postales con un número de dígitos menor a 5. Estas tres situaciones podrían tratarse de datos atípicos por errosres de digitación de la información de registro y deberán ser validadas con el negocio para determinar como poceder con dichos valores en caso de que sean un problema. Mientras tanto, podemos profundizar más en este problema de consistencia de datos numéricos con el objetivo de revisar que tanto se repite esta posible inconsitencia y dar un primer acercamiento a saber si son o no problemas de calidad.

In [12]:
#revisemos con más detalle como se comportan algunas de las columnas de precio, longitud_nombre_producto y codigo_postal_vendedor.
data_ordenes[["precio"]].value_counts().reset_index().sort_values(by="precio")
Out[12]:
precio count
580 0.01 2
6713 0.03 1
249 0.04 3
5987 0.05 1
5986 0.08 1
... ... ...
3487 852.29 1
3486 884.85 1
3485 995.58 1
3484 1003.57 1
8378 1262.94 1

8379 rows × 2 columns

Análisis del atributo precio: vemos que el precio va aumentando gradualmente desde 0.01 y va incrementando el número de cifras de una manera progresiva; vemos que no es un caso aislado el hecho de que el precio tenga un valor mínimo tan bajo. De igual manera es importante confirmar con el negocio si estos valores son o no erroneos.

In [13]:
#revisamos con más detalle el atributo asociado al código postal del vendedor.
data_ordenes[["codigo_postal_vendedor"]].value_counts().reset_index().sort_values(by="codigo_postal_vendedor")
Out[13]:
codigo_postal_vendedor count
15 5001 204
30 5002 144
67 5004 15
12 8001 224
21 11001 178
... ... ...
29 91001 145
25 94001 158
45 95001 92
18 97001 187
64 99001 22

71 rows × 2 columns

In [14]:
#identificamos las ciudades a las que representan dichos códigos postales.
data_codigo=data_ordenes.groupby(["codigo_postal_vendedor","ciudad_vendedor"]).count()[
    "departamento_vendedor"].reset_index(name="Conteo")
data_codigo
Out[14]:
codigo_postal_vendedor ciudad_vendedor Conteo
0 5001 Medellin 204
1 5002 Abejorral 144
2 5004 Abriaqui 15
3 8001 Barranquilla 224
4 11001 Bogota d.c. 178
... ... ... ...
66 91001 Leticia 145
67 94001 Inirida 158
68 95001 San jose del guaviare 92
69 97001 Mitu 187
70 99001 Puerto carreño 22

71 rows × 3 columns

In [15]:
#verificamos si hay tantos códigos postales como ciudades en el conjunto de datos, determinando la
#cantidad de valores únicos en cada atrinuto
print("Valores únicos de códigos postales:",data_codigo["codigo_postal_vendedor"].unique().shape)
print("Valores únicos ciudades:",data_codigo["ciudad_vendedor"].unique().shape)
Valores únicos de códigos postales: (71,)
Valores únicos ciudades: (71,)

Análisis del atributo codigo_postal_vendedor: podemos observar que hay 4 cados dónde el código postal tiene solo 4 digítos, que no es solo el caso del valor mínimo, por lo cual este caso no es aislado. Para profundizar en este caso comparamos el código postal del vendedor junto con el nombre de la ciudad de este, con el fin de determinar si estos código de 4 dígitos son correctos o es por una omisión de algún dígito al momento del registro. Observamos que la cantidad de valores únicos en cada atributo son iguales, por lo cual se descarta la posibilidad de los códigos con un número de 4 dígitos sean errores de consistencia.

In [16]:
#revisamos con más detalle el atributo asociado a la longitud del nombre del producto.
data_ordenes[["longitud_nombre_producto"]].value_counts().reset_index().sort_values(by="longitud_nombre_producto").head(15)
Out[16]:
longitud_nombre_producto count
40 0.0 207
32 1.0 233
39 2.0 224
17 3.0 247
35 4.0 230
21 5.0 245
22 6.0 244
0 7.0 271
4 8.0 266
5 9.0 265
6 10.0 263
10 11.0 260
25 12.0 241
38 13.0 227
31 14.0 236

Análisis del atributo longitud_nombre_producto: observamos que en total hay 207 productos que aparentemente no tienen un nombre asociado en los registros, un total de 233 que tienen por nombre un solo caracter y 224 que tienen solo 2 caracteres en su nombre. En primer lugar, lo ideal, sería validar con el negocio a ver si esta información se refleja de igual manera en la plataforma digital o si es un error al momento de descargar el conjunto de datos. Del mismo modo se deberán validar los valores que parecen ser atípicos en las otras categorías de las características del producto.

3. Análisis estadístico univariado¶

Objetivos¶

  1. Determinar cual es el comportamiento estadístico de los atributos numéricos del dataset.
  2. Identificar cuales son las categorías de producto más vendidas a nivel nacional y cuales son aquellas que componen el 20% de las ventas principales del negocio con el fin de aplicar un descuento al precio de venta sobre estas.
  3. Determinar cual el porcentaje de los productos que pesan menos de 1000 g con el fin de aplicar un descuento sobre el valor del flete de estos productos.
In [17]:
#revisamos las principales variables estadísticas del conjunto de datos, tales como media, desviación estandar,
#y percentiles del 25, 50 y 75%.
data_ordenes.describe()
Out[17]:
fecha_envio_limite precio valor_flete codigo_postal_vendedor longitud_nombre_producto longitud_descripcion_producto cantidad_fotos_producto peso_g_producto longitud_cm_producto altura_cm_producto ancho_cm_producto
count 10111 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.000000 10111.00000
mean 2018-01-03 05:02:30.406488064 119.868468 20.062207 49995.607457 20.070023 19.844724 20.097616 2106.475522 30.067352 17.911186 22.91257
min 2017-07-13 22:38:00 0.010000 0.000000 5001.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.00000
25% 2017-10-08 11:40:00 34.175000 5.760000 50001.000000 10.000000 10.000000 10.000000 607.000000 19.000000 9.000000 15.00000
50% 2018-01-03 06:13:00 83.180000 13.990000 52323.000000 20.000000 20.000000 20.000000 1459.000000 30.000000 17.000000 23.00000
75% 2018-04-01 03:34:30 165.640000 27.475000 54003.000000 30.000000 30.000000 30.000000 2941.000000 41.000000 26.000000 30.00000
max 2018-06-26 02:19:00 1262.940000 183.150000 99001.000000 40.000000 40.000000 40.000000 20661.000000 91.000000 64.000000 72.00000
std NaN 119.386311 20.111832 22461.742889 11.719844 11.851631 11.802373 2094.402206 15.286299 11.359838 11.15189

A partir de esta primera descripción estadísticas de los datos podemos tener un acercamiento a la forma de distribución de los atributos. Al observar el valor del percentil 50 y el valor máximo del precio de venta, nos damos cuenta que los precios de ventas presentan una asimetría positiva debido a que los datos se concentran en mayor cantidad a la izquierda con un sesgo a la derecha; este también es el caso para el valor del flete, el peso del producto vendido y y las dimensiones del producto. Sin embargo, la concentración de los datos hacia la izquierda es mucho mayor en los atributos de precio, valor del flete y peso del producto.

Para el caso de los atributos relacionados con las características del nombre del producto y la descripción de este, de acuerdo con el valor de su mediana y el valor máximo registrado, se observa que presentan una distribución simétrica.

Contexto: desde el negocio están interesados en conocer cuáles son las categorías de productos más vendidas a nivel nacional, del mismo modo que conocer cuales son aquellas categorías que contribuyen al 20% de las ventas principales en el negocio, esto con el fin de diseñar una estrategia de negocio enfocada en dichas categorías en la que se buscará realizar un descuento sobre estas.

In [18]:
#Para conocer cuáles son las categorías de productos más vendidas calcularemos la distribución de frecuencias de este atributo. 

#Calculamos la frecuencia absoluta de las distintas categorías.
frec_productos=data_ordenes['nombre_categoria_producto'].value_counts().reset_index()
frec_productos=frec_productos.rename(columns={'count':'fi'})
#Calculamos la frecuencia relativa.
frec_productos['hi %']=frec_productos['fi'].apply(lambda x:((x/frec_productos['fi'].sum())*100).round(1))
#Calculamos ahora la frecuencia absoluta acumulada y relativa acumulada.
frec_productos['Fi']=frec_productos['fi'].cumsum() #frecuencia absoluta acumulada.
frec_productos['Hi %']=frec_productos['hi %'].cumsum() #frecuencia relativa acumulada.
frec_productos
Out[18]:
nombre_categoria_producto fi hi % Fi Hi %
0 Tecnología 542 5.4 542 5.4
1 Deportes 537 5.3 1079 10.7
2 Frutas y verduras 531 5.3 1610 16.0
3 Carnicería 523 5.2 2133 21.2
4 Ropa de adultos 521 5.2 2654 26.4
5 Ferretería 518 5.1 3172 31.5
6 Juguetes 516 5.1 3688 36.6
7 Ropa infantil 511 5.1 4199 41.7
8 Electrodomésticos 509 5.0 4708 46.7
9 Dormitorio 508 5.0 5216 51.7
10 Lácteos 499 4.9 5715 56.6
11 Libros 497 4.9 6212 61.5
12 Productos ecoamigables 497 4.9 6709 66.4
13 Mascotas 495 4.9 7204 71.3
14 Tarjetas regalo 495 4.9 7699 76.2
15 Salud 488 4.8 8187 81.0
16 Celulares 488 4.8 8675 85.8
17 Muebles 486 4.8 9161 90.6
18 Licor 475 4.7 9636 95.3
19 Bebés 475 4.7 10111 100.0

Productos principales: podemos observar que a nivel nacional los productos contribuyen a las ventas de una forma casi uniforme, donde cada uno de estos productos tiene un peso en las ventas de aproximadamente el 5%, por lo cual podría decirse que a pesar de que hay algunas categorías que son primeras en ventas, el 50% de las ventas del negocio será alcanzado siempre con la mitad de las categorías existentes, sin importar, cual de ellas sean escogidas, de acuerdo con los datos actuales.

Por otro lado, las categorías de Tecnología, Deportes, Frutas y verduras, y Carnicería deberán ser las escogidas para aplicar la estaregia de descuento si se quiere impactar sobre el 20% principal de las ventas.

In [19]:
#vamos a visualizar en un gráfico de pastel como es el comportamiento de las ventas a nivel nacional.
fig = px.pie(frec_productos,values="fi",names="nombre_categoria_producto",
             title="Comportamiento de las ventas a nivel nacional")

Contexto: desde el negocio se ha decido que se quiere aplicar una estrategia de negocio adicional, y para esto desean realizar una campaña de descuento enfocada en el valor del flete de envío de los productos, este descuento en alianza con la empresa de logística, se podrá aplicar solo a aquellos productos que tengan un peso menor a 1000 g.

De acuerdo a lo anterior, la empresa desea conocer cuál es el porcentaje de los productos vendidos al cual se le podrá aplicar dicho descuento y conocer las categorías que se verán impactas.

In [20]:
#a partir de la descripción estadística previa realizada sobre los datos, sabemos que el porcentaje de productos con un peso 
#menor o igual a 1000 gr se encuentra entre 25% y 50%. Por ello procedemos a encontrar el percentil en este rango. 

#creamos un diccionario para guardar los resultados de percentil y peso del producto.
percentiles={}
rango_min=0.25 #rango de percentil mínimo de búsqueda.
rango_max=0.50 #rango de percentil máximo de búsqueda.
valor_deseado=1000 #peso máximo permitido.

#creamos un ciclo que itere entre el rango propuesto.
for i in np.arange(rango_min,rango_max,0.01):
    if (data_ordenes["peso_g_producto"].quantile(i) - valor_deseado) <= 0: 
        #guardamos todos los resultados menores o iguales a 1000 g.
        percentiles[round(i,2)]=round(data_ordenes["peso_g_producto"].quantile(i),0)

#imprimimos el percentil que proporciona el peso de producto más cercano a 1000 g.
print("El porcentaje de productos con un peso menor o igual a 1000 es de",max(percentiles.keys())*100,"%")
El porcentaje de productos con un peso menor o igual a 1000 es de 37.0 %
In [21]:
#Encontremos aquellas categorías que tienen productos con un peso menor a 1000 g y realizamos un conteo de productos. 
prod_descuento=data_ordenes.loc[data_ordenes["peso_g_producto"]<=1000,
                                "nombre_categoria_producto"].value_counts().reset_index(name="En descuento")
#adicionamos la frecuencia absoluta de cada categoría en el conjunto de datos total.
prod_descuento=pd.merge(prod_descuento,frec_productos[["nombre_categoria_producto","fi"]],
                        on="nombre_categoria_producto",how="inner")
#calculamos que % de productos están en descuento dentro de cada categoría.
prod_descuento["% de categoría"]=round((prod_descuento["En descuento"]/prod_descuento['fi'])*100,0)
#calculamos el % de productos por cada categoría que está en descuendo dentro del total de productos en venta.
prod_descuento["% de productos"]=round((prod_descuento["En descuento"]/prod_descuento['fi'].sum())*100,1)
prod_descuento
Out[21]:
nombre_categoria_producto En descuento fi % de categoría % de productos
0 Ropa de adultos 210 521 40.0 2.1
1 Electrodomésticos 202 509 40.0 2.0
2 Mascotas 200 495 40.0 2.0
3 Carnicería 199 523 38.0 2.0
4 Deportes 199 537 37.0 2.0
5 Libros 197 497 40.0 1.9
6 Tecnología 195 542 36.0 1.9
7 Frutas y verduras 194 531 37.0 1.9
8 Tarjetas regalo 194 495 39.0 1.9
9 Juguetes 192 516 37.0 1.9
10 Dormitorio 192 508 38.0 1.9
11 Muebles 191 486 39.0 1.9
12 Lácteos 191 499 38.0 1.9
13 Productos ecoamigables 191 497 38.0 1.9
14 Ferretería 190 518 37.0 1.9
15 Celulares 189 488 39.0 1.9
16 Salud 181 488 37.0 1.8
17 Ropa infantil 175 511 34.0 1.7
18 Licor 167 475 35.0 1.7
19 Bebés 164 475 35.0 1.6
In [22]:
#visualicemos la cantidad de productos en descuento.
#creamos un dataframe para identificar el total de productos en descuentos y el total de productos que no están en descuento. 
proporcion_desc=pd.DataFrame()
proporcion_desc["Estado del producto"]="En descuento","Sin descuento"
proporcion_desc["Cantidad"] = [(prod_descuento["En descuento"].sum()),
                               (-prod_descuento["En descuento"].sum()+prod_descuento['fi'].sum())]
#construimos el gráfico de pastel para visualizar los datos.
fig1 = px.pie(proporcion_desc,values="Cantidad",names="Estado del producto",
             title="Proporción de productos en descuento")
In [23]:
#vamos a visualizar en un gráfico de pastel como se distribuye el descuento en productos con un peso menor a 1000 g. 
fig2 = px.pie(prod_descuento,values="En descuento",names="nombre_categoria_producto",
             title="Contribución de cada categoría a los productos en descuento")
In [24]:
#vamos a visualizar en un gráfico de barras como se distribuye el descuento a nivel de categorías.
#creamos colores aleatorias para la figura.
get_colors = lambda n: list(map(lambda i: "#" + "%06x" % random.randint(0, 0xFFFFFF),range(n)))
colores=get_colors(len(prod_descuento))
#creamos la figura con Plotly.
fig3 = px.bar(prod_descuento,x="% de categoría",y="nombre_categoria_producto",color="nombre_categoria_producto",
            color_discrete_sequence=colores,title="Proporción de productos en descuento según su categoría")
#cambiamos el grosor de las barras para que sean más legibles.
for bar in fig3.data:
    bar.width = 0.4
In [25]:
#vamos a visualizar en un gráfico de barras como se distribuye el descuento a nivel total de productos constrastado con a nivel
#de categorías.
fig4 = px.bar(prod_descuento,y=["% de productos","% de categoría"],x="nombre_categoria_producto",barmode="group",
            title="Proporción de productos en descuento")
#cambiamos el grosor de las barras para que sean más legibles.
for bar in fig4.data:
    bar.width = 0.4

Cantidad de productos aceptables: la estrategia de negocio basada en un descuento al valor del envío se podrá aplicar solo al 37% de los productos y se podrán incluir en el descuento todas las categorías de venta del negocio. Los productos que estarán en descuentos representan para cada categoría entre un 35 y 40% de su totalidad; y representan entre un 1.6 y 2.1% del total de productos vendidos en el negocio por cada categoría en descuento.

In [26]:
fig.show(),fig1.show(),fig2.show(),fig3.show(),fig4.show()
Out[26]:
(None, None, None, None, None)

Conclusión del análisis de negocio¶

Al describir los datos de manera estadística y al observar el valor del percentil 50 y el valor máximo del precio de venta, nos dimos cuenta que los precios de venta presentan una asimetría positiva debido a que los datos se concentran en mayor cantidad a la izquierda con un sesgo a la derecha; este también es el caso para el valor del flete, el peso del producto vendido y y las dimensiones del producto. Sin embargo, la concentración de los datos hacia la izquierda es mucho mayor en los atributos de precio, valor del flete y peso del producto.

Para el caso de los atributos relacionados con las características del nombre del producto y la descripción de este, de acuerdo con el valor de su mediana y el valor máximo registrado, se observa que presentan una distribución simétrica.

Desde el punto de vista del negocio, podemos observar que a nivel nacional los productos contribuyen a las ventas de una forma casi uniforme, donde cada uno de estos productos tiene un peso en las ventas de aproximadamente el 5%, por lo cual podría decirse que a pesar de que hay algunas categorías que son primeras en ventas, el 50% de las ventas del negocio será alcanzado siempre con la mitad de las categorías existentes, sin importar, cual de ellas sean escogidas, de acuerdo con los datos actuales.

Como estrategia de negocio, las categorías de Tecnología, Deportes, Frutas y verduras, y Carnicería deberán ser las escogidas para aplicar la estaregia de descuento sobre el precio de producto si se quiere impactar sobre el 20% principal de las ventas. Adicionalmente, la estrategia de negocio basada en un descuento al valor del envío se podrá aplicar solo al 37% de los productos y se podrán incluir en el descuento todas las categorías de venta del negocio. Los productos que estarán en descuentos representan para cada categoría entre un 35 y 40% de su totalidad; y representan entre un 1.6 y 2.1% del total de productos vendidos en el negocio por cada categoría en descuento.